﻿using System;
using System.IO;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.DataSourcesOleDB;
using ESRI.ArcGIS.GeoDatabaseExtensions;
using ESRI.ArcGIS.DataManagementTools;
using ESRI.ArcGIS.Geometry;


namespace PlanningGIS.ArcGIS
{
    /// <summary>
    /// 工作空间操作类
    /// </summary>
    public class WorkspaceHelper
    {
        /// <summary>
        /// 创建或打开工作空间，支持mdb、gdb、文件数据（shp、dwg、栅格等），sde仅只支持打开
        /// </summary>
        /// <param name="fullname">数据库文件所在的全路径</param>
        /// <param name="extension">扩展的类型：".shp"、".dwg"、".jpg"</param>
        /// <returns></returns>
        public static IWorkspace CreateOrOpenWorksapce(string fullname, string extension = ".shp")
        {
            if (fullname.ToLower().EndsWith(".mdb") || fullname.ToLower().Contains(".mdb\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".mdb\\")) p = fullname.Trim().Substring(0, fullname.LastIndexOf("\\"));
                if (File.Exists(p)) return OpenAccessWorkspace(p);
                else return CreateAccessWorkspace(p);
            }
            else if (fullname.ToLower().EndsWith(".gdb") || fullname.ToLower().Contains(".gdb\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".gdb\\")) p = fullname.Trim().Substring(0, fullname.LastIndexOf("\\"));
                if (Directory.Exists(p)) return OpenGDBWorkspace(p);
                else return CreateGDBWorkspace(p);
            }
            else if (fullname.ToLower().EndsWith(".sde") || fullname.ToLower().Contains(".sde\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".sde\\")) p = fullname.Trim().Substring(0, fullname.LastIndexOf("\\"));
                return OpenSDEWorkspaceFromFile(p);
            }
            else
            {
                if (!Directory.Exists(fullname)) Directory.CreateDirectory(fullname);
                if (".dwg".Equals(extension) || ".dxf".Equals(extension))
                {
                    return OpenCADWorkspace(fullname);
                }
                else if (".shp".Equals(extension))
                {
                    return OpenShpWorkspace(fullname);
                }
                else
                {
                    return OpenShpWorkspace(fullname);
                }
            }

        }

        #region 创建工作空间
        /// <summary>
        /// 创建个人空间数据库(MDB)，并返回创建后的工作空间
        /// </summary>
        /// <param name="fullname">文件夹路径名("C:\\temp\\MyNewDB.mdb")</param>
        public static IWorkspace CreateAccessWorkspace(string fullname)
        {
            string path = System.IO.Path.GetDirectoryName(fullname);
            string filename = System.IO.Path.GetFileName(fullname);
            if (Directory.Exists(path) == false)
                Directory.CreateDirectory(path);
            IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactory() as IWorkspaceFactory;
            IWorkspaceName workspaceName = workspaceFactory.Create(path, filename, null, 0);
            ESRI.ArcGIS.esriSystem.IName name = (ESRI.ArcGIS.esriSystem.IName)workspaceName;
            IWorkspace pGDB_workspace = (IWorkspace)name.Open();
            return pGDB_workspace;
        }

        /// <summary>
        /// 创建文件空间数据库(GDB)，并返回创建后的工作空间
        /// </summary>
        /// <param name="fullname">文件夹路径名("C:\\temp\\MyNewDB.gdb")</param>
        /// <returns></returns>
        public static IWorkspace CreateGDBWorkspace(string fullname)
        {
            DirectoryInfo di = new DirectoryInfo(fullname);
            string folderPath = di.Parent.FullName;
            string filename = di.Name;
            if (Directory.Exists(folderPath) == false)
                Directory.CreateDirectory(folderPath);
            IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactory() as IWorkspaceFactory;
            IWorkspaceName workspaceName = workspaceFactory.Create(folderPath, filename, null, 0);
            ESRI.ArcGIS.esriSystem.IName name = (ESRI.ArcGIS.esriSystem.IName)workspaceName;
            IWorkspace fileGDB_workspace = (IWorkspace)name.Open();
            return fileGDB_workspace;
        }
        
        /// <summary>
        /// 创建SDE空间数据库，并返回创建后的工作空间
        /// </summary>
        /// <param name="propertySet">sde连接数据</param>
        /// <param name="fullname">文件夹路径名("C:\\temp\\SDE_Connection.sde")</param>
        /// <returns></returns>
        public static IWorkspace CreateSDEWorkspace(IPropertySet propertySet, string fullname)
        {
            string folderPath = System.IO.Path.GetDirectoryName(fullname);
            string filename = System.IO.Path.GetFileName(fullname);
            IWorkspaceFactory workspaceFactory = new SdeWorkspaceFactory() as IWorkspaceFactory;
            IWorkspaceName workspaceName = workspaceFactory.Create(folderPath, filename, propertySet, 0);
            IName name = (IName)workspaceName;
            IWorkspace sde_workspace = (IWorkspace)name.Open();
            return sde_workspace;
        }

        /// <summary>
        /// 创建激光雷达数据集lasd
        /// </summary>
        /// <param name="fullname">文件夹路径名("C:\\temp\\lasdataset.las")</param>
        /// <param name="spatialReference">空间参考</param>
        /// <param name="message">消息</param>
        /// <returns></returns>
        public static bool CreateLasWorkspace(string fullname, ISpatialReference spatialReference,out string message)
        {
            message = "";
            string folderPath = System.IO.Path.GetDirectoryName(fullname);
            string filename = System.IO.Path.GetFileName(fullname);
            if (Directory.Exists(folderPath) == false)
                Directory.CreateDirectory(folderPath);            
            CreateLasDataset createLasDs = new CreateLasDataset();  //创建LasDataset
            string lasDsFile = fullname.Substring(0, fullname.Length - 3) + "lasd";
            createLasDs.input = fullname;
            createLasDs.out_las_dataset = lasDsFile;
            if (spatialReference != null)
                createLasDs.spatial_reference = spatialReference;
            bool suc = GeoprocessorHelper.Execute(createLasDs);
            if (!suc) message = GeoprocessorHelper.GetMessage();
            return suc;
        }

        #endregion

        #region 打开工作空间

        /// <summary>
        /// 打开文件工作空间
        /// </summary>
        /// <param name="fullname">全路径</param>
        /// <returns></returns>
        public static IWorkspace OpenWorkspace(string fullname)
        {
            if (fullname.Trim().ToLower().EndsWith(".mdb"))
                return OpenAccessWorkspace(fullname);
            else if (fullname.Trim().ToLower().EndsWith(".gdb"))
                return OpenGDBWorkspace(fullname);
            else if (fullname.Trim().ToLower().EndsWith(".sde"))
                return OpenSDEWorkspaceFromFile(fullname);
            return null;
        }

        /// <summary>
        /// 打开工作空间，扩展方法，允许在路径后面跟着要素类的名称
        /// </summary>
        /// <param name="fullname"></param>
        /// <returns></returns>
        public static IWorkspace OpenWorkspace2(string fullname)
        {
            if (string.IsNullOrWhiteSpace(fullname)) return null;
            fullname = fullname.Trim();
            IWorkspace workspace = null;
            if (fullname.ToLower().EndsWith(".gdb") || fullname.ToLower().Contains(".gdb\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".gdb\\"))
                    p = fullname.Substring(0, fullname.LastIndexOf(".gdb\\") + 4);
                workspace = WorkspaceHelper.OpenGDBWorkspace(p);
            }
            else if (fullname.ToLower().EndsWith(".mdb") || fullname.ToLower().Contains(".mdb\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".mdb\\"))
                    p = fullname.Trim().Substring(0, fullname.LastIndexOf(".mdb\\")+4);
                workspace = WorkspaceHelper.OpenAccessWorkspace(p);
            }
            else if (fullname.ToLower().EndsWith(".sde") || fullname.ToLower().Contains(".sde\\"))
            {
                string p = fullname;
                if (fullname.ToLower().Contains(".sde\\"))
                    p = fullname.Trim().Substring(0, fullname.LastIndexOf(".sde\\")+4);
                workspace = WorkspaceHelper.OpenSDEWorkspaceFromFile(p);
            }
            else if (Directory.Exists(fullname))
            {
                workspace = WorkspaceHelper.OpenShpWorkspace(fullname);
            }
            return workspace;
        }

        /// <summary>
        /// 打开 CAD 工作空间。当路径不存在时异常
        /// </summary>
        /// <param name="fullname">cad 文件所在路径。</param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenCADWorkspace(string fullname)
        {
            if (!Directory.Exists(fullname)) return null;
            return new CadWorkspaceFactory().OpenFromFile(fullname, 0);
        }

        /// <summary>
        /// 打开 Shp 工作空间。当路径不存在时异常
        /// </summary>
        /// <param name="fullname">shp 文件所在路径。</param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenShpWorkspace(string fullname)
        {
            if (!Directory.Exists(fullname)) return null;
            return new ShapefileWorkspaceFactory().OpenFromFile(fullname, 0);
        }
        
        /// <summary>
        /// 打开个人数据库工作空间
        /// </summary>
        /// <param name="fullname">mdb全路径"E:\\canada\\canada.mdb"  </param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenAccessWorkspace(string fullname)
        {
            if (!File.Exists(fullname)) return null;
            return (new AccessWorkspaceFactory() as IWorkspaceFactory).OpenFromFile(fullname, 0);
        }

        /// <summary>
        /// 打开文件数据库工作空间
        /// </summary>
        /// <param name="fullname">gdb全路径"E:\\canada\\canada.gdb"  </param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenGDBWorkspace(string fullname)
        {
            if (!Directory.Exists(fullname)) return null;
            return ((IWorkspaceFactory)(new FileGDBWorkspaceFactory())).OpenFromFile(fullname, 0);
        }

        /// <summary>
        /// 根据连接字符串打开一个SDE工作空间，格式为：
        /// 或 Instance=sde:oracle$126.33.9.157/orcl;User=micgis;Password=micgis;DBCLIENT=oracle ；
        /// 或 Instance=sde:oracle11g:orcl;User=micgis;Password=micgis;DBCLIENT=oracle ；
        /// </summary>
        /// <param name="connectstring">SDE 连接字符串。</param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenSdeWorkspaceFromString(string connectstring)
        {
            return (new SdeWorkspaceFactory() as IWorkspaceFactory2).OpenFromString(connectstring, 0);
        }

        /// <summary>
        /// 根据本地文件，打开SDE工作空间
        /// </summary>
        /// <param name="fullname">"E:\\canada\\canada.sde"</param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenSDEWorkspaceFromFile(string fullname)
        {
            return (new SdeWorkspaceFactory() as IWorkspaceFactory2).OpenFromFile(fullname, 0);
        }

        /// <summary>
        /// 打开 SDE 工作空间
        /// </summary>
        /// <param name="propertySet">连接属性</param>
        /// <returns>工作空间</returns>
        public static IWorkspace OpenSDEWorkspace(IPropertySet propertySet)
        {
            return (new SdeWorkspaceFactory() as IWorkspaceFactory2).Open(propertySet, 0);
        }

        /// <summary>
        /// 打开 SDE 工作空间
        /// </summary>
        /// <param name="ip">ip地址</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="sid">oracle的实例名</param>
        /// <returns></returns>
        public static IWorkspace OpenSDEWorkspace(string ip, string username, string password, string sid = "orcl")
        {
            if (ip.ToLower().Contains("sde:oracle$")) ip = ip.ToLower().Replace("sde:oracle$", "");
            string connectstring = string.Format("Instance=sde:oracle${0}/{1};User={2};Password={3};DBCLIENT=oracle", ip, sid, username, password);
            return (new SdeWorkspaceFactory() as IWorkspaceFactory2).OpenFromString(connectstring, 0);
        }

        /// <summary>
        /// 打开SDE工作空间（直连PostgreSql数据库）
        /// 需要将libeay32.dll；libiconv-2.dll；libintl-8.dll；libpq.dll；ssleay32.dll文件拷贝到运行程序目录下
        /// </summary>
        /// <param name="serverIP">ip地址</param>
        /// <param name="user">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="database">数据库名称</param>
        /// <param name="version">sde版本</param>
        /// <returns></returns>
        public static IWorkspace OpenNpgsqlSDEWorkspace(string serverIP, string user, string password, string database, string version = "sde.DEFAULT")
        {
            string instance = string.Format("sde:postgresql:{0}", serverIP);
            IPropertySet pPropertySet = new PropertySetClass();
            pPropertySet.SetProperty("USER", user);
            pPropertySet.SetProperty("PASSWORD", password);
            pPropertySet.SetProperty("VERSION", version);
            pPropertySet.SetProperty("INSTANCE", instance);
            pPropertySet.SetProperty("DATABASE", database);
            return OpenSDEWorkspace(pPropertySet);
        }

        /// <summary>
        /// 根据数据库连接打开 OLEDB 工作空间
        /// </summary>
        /// <param name="connectstring"></param>
        /// <returns></returns>
        public static IWorkspace OpenOLEDBWorkspace(string connectstring)
        {
            IWorkspaceFactory2 pOleWksFac = new OLEDBWorkspaceFactory() as IWorkspaceFactory2;
            ESRI.ArcGIS.esriSystem.PropertySet propertySet = new ESRI.ArcGIS.esriSystem.PropertySet();
            propertySet.SetProperty("CONNECTSTRING", "Provider=MSDAORA.1;" + connectstring);
            return pOleWksFac.Open(propertySet, 0);
        }

        /// <summary>
        /// 打开栅格文件工作空间
        /// </summary>
        /// <param name="fullname">栅格文件路径</param>
        /// <returns></returns>
        public static IWorkspace OpenRasterWorkspace(string fullname)
        {
            return (new RasterWorkspaceFactory()).OpenFromFile(fullname, 0);
        }

        /// <summary>
        /// 打开激光雷达工作空间 ILasDatasetWorkspace
        /// </summary>
        /// <param name="fullname"></param>
        /// <returns></returns>
        public static IWorkspace OpenLasWorkspace(string fullname)
        {
            return (new LasDatasetWorkspaceFactory() as IWorkspaceFactory2).OpenFromFile(System.IO.Path.GetDirectoryName(fullname), 0);            
        }
        #endregion

        #region 获取对象的工作空间

        /// <summary>
        /// 获取数据集所在的工作空间
        /// </summary>
        /// <param name="featureClass">数据集</param>
        /// <returns></returns>
        public static IWorkspace GetWorkspace(IFeatureClass featureClass)
        {
            if (featureClass == null) return null;
            IDataset dataset = (IDataset)featureClass;
            return dataset.Workspace;
        }

        #endregion 

        #region 连接属性

        /// <summary>
        /// 获取连接属性默认存储的全路径名称
        /// </summary>
        /// <param name="propertySet">连接属性</param>
        /// <returns></returns>
        public static string GetPropertyDefaultName(IPropertySet propertySet)
        {
            string ip = propertySet.GetProperty("Instance").ToString();
            string[] temps = ip.Split('$');
            if (temps.Length == 2)
                ip = temps[1].Trim();
            temps = ip.Split('/');
            if (temps.Length == 2)
                ip = temps[0].Trim();
            string fullname = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\ESRI\Desktop10.5\ArcCatalog\";
            fullname += ip + "_" + propertySet.GetProperty("User").ToString() + ".sde";
            return fullname;
        }

        /// <summary>
        /// 保存连接属性信息
        /// </summary>
        /// <param name="propertySet">sde连接数据</param>
        /// <param name="fullname">文件夹路径名("C:\temp\SDE_Connection.sde")</param>
        /// <returns></returns>
        public static void SavePropertySet(IPropertySet propertySet, string fullname)
        {
            if (File.Exists(fullname)) return;
            string folderPath = System.IO.Path.GetDirectoryName(fullname);
            string filename = System.IO.Path.GetFileName(fullname);
            if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
            IWorkspaceFactory workspaceFactory = new SdeWorkspaceFactory() as IWorkspaceFactory;
            workspaceFactory.Create(folderPath, filename, propertySet, 0);
        }

        /// <summary>
        /// 从sde连接文件中读取sde连接信息
        /// </summary>
        /// <param name="fullname">sde连接文件全路径:"E:\\canada\\canada.sde"</param>
        /// <returns></returns>
        public static IPropertySet GetPropertiesFromFile(string fullname)
        {
            return (new SdeWorkspaceFactory() as IWorkspaceFactory).ReadConnectionPropertiesFromFile(fullname);
        }

        /// <summary>
        /// 从连接字符串中获取连接信息
        /// </summary>
        /// <param name="connectstring">连接信息</param>
        /// <returns></returns>
        public static IPropertySet GetPropertiesFromString(string connectstring)
        {
            ESRI.ArcGIS.esriSystem.IPropertySet properSet = new ESRI.ArcGIS.esriSystem.PropertySet();
            string[] arrray = connectstring.Split(';');
            foreach (string str in arrray)
            {
                if (str.ToLower().Contains("server") && str.Contains("="))
                {
                    properSet.SetProperty("Server", str.Substring(str.IndexOf("=") + 1).Trim());
                    continue;
                }
                if (str.ToLower().Contains("instance") && str.Contains("="))
                {
                    properSet.SetProperty("Instance", str.Substring(str.IndexOf("=") + 1).Trim());
                    continue;
                }
                if (str.ToLower().Contains("user") && str.Contains("="))
                {
                    properSet.SetProperty("User", str.Substring(str.IndexOf("=") + 1).Trim());
                    continue;
                }
                if (str.ToLower().Contains("password") && str.Contains("="))
                {
                    properSet.SetProperty("Password", str.Substring(str.IndexOf("=") + 1).Trim());
                    continue;
                }
                if (str.ToLower().Contains("version") && str.Contains("="))
                {
                    properSet.SetProperty("Version", str.Substring(str.IndexOf("=") + 1).Trim());
                    continue;
                }
            }
            return properSet;
        }
                
        /// <summary>
        /// 获得一个要素类的某项连接信息，例如给出vName="instance"，则返回实例信息
        /// </summary>
        /// <param name="featCls">要素类</param>
        /// <param name="name">连接信息字段</param>
        /// <returns>连接信息</returns>
        public static string GetConnectProperty(IFeatureClass featCls, string name)
        {
            return GetConnectProperty((featCls as IDataset).Workspace, name);
        }

        /// <summary>
        /// 获取工作空间的连接属性信息
        /// </summary>
        /// <param name="workspace"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetConnectProperty(IWorkspace workspace, string name)
        {
            object propertyNames;
            object propertyValues;
            workspace.ConnectionProperties.GetAllProperties(out propertyNames, out propertyValues);
            System.Array propNameArray = (System.Array)propertyNames;
            System.Array propValuesArray = (System.Array)propertyValues;
            for (int i = 0; i < propNameArray.Length; i++)
            {
                if (propNameArray.GetValue(i).ToString().ToUpper() == name.ToUpper())
                {
                    return propValuesArray.GetValue(i).ToString();
                }
            }
            return "";
        }

        /// <summary>
        /// 获取工作空间的连接附加信息
        /// </summary>
        /// <param name="workspace"></param>
        /// <returns></returns>
        public static string GetConnectionAffix(IWorkspace workspace)
        {
            if (workspace.PathName != "")
            {
                return workspace.PathName;
            }
            else
            {
                return GetConnectionAffix(workspace.ConnectionProperties);
            }
        }

        /// <summary>
        /// 获取工作空间的连接附加信息
        /// </summary>
        /// <param name="propertySet"></param>
        /// <returns></returns>
        public static string GetConnectionAffix(IPropertySet propertySet)
        {
            string conn = "";
            object names;
            object values;
            propertySet.GetAllProperties(out names, out values);
            object[] valuearr = values as object[];
            object[] namearr = names as object[];
            if (valuearr.GetLength(0) == 1)
                return valuearr[0].ToString();
            else if (valuearr.GetLength(0) > 1)
            {
                for (int i = 0; i < propertySet.Count; i++)
                {
                    string name = namearr[i].ToString().ToUpper();
                    if (name != "DATABASE" && name != "PASSWORD" && name != "VERSION" && name != "AUTHENTICATION_MODE")
                    {
                        conn = conn + "," + valuearr[i];
                    }
                }
                conn = conn.Substring(1, conn.Length - 1);//去掉第一个逗号
            }
            return conn;
        }

        #endregion
        
        #region 编辑
        /// <summary>
        /// 开始编辑
        /// </summary>
        /// <param name="workspace"></param>
        public static void StartEdit(IWorkspace workspace)
        {
            IWorkspaceEdit edit = workspace as IWorkspaceEdit;
            if (!edit.IsBeingEdited())
            {
                edit.StartEditing(true);
                edit.StartEditOperation();
            }
        }

        /// <summary>
        /// 停止编辑
        /// </summary>
        /// <param name="workspace"></param>
        /// <param name="issave"></param>
        public static void StopEdit(IWorkspace workspace, bool issave = true)
        {
            IWorkspaceEdit edit = workspace as IWorkspaceEdit;
            if (edit.IsBeingEdited())
            {
                edit.StopEditOperation();
                edit.StopEditing(issave);
            }
        }

        /// <summary>
        /// 保存编辑
        /// </summary>
        /// <param name="workspace"></param>
        public static void SaveEdit(IWorkspace workspace)
        {
            StopEdit(workspace, true);
            StartEdit(workspace);
        }
        #endregion

    }
}
